package com.hjx.coverage;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.script.ScriptContext;
import javax.script.ScriptEngine;
import javax.script.ScriptException;
import jscover.Main;
import jscover.instrument.handler.SourceHandlerRegister;
import jscover.report.JSONDataMerger;
import jscover.util.IoUtils;
import org.apache.commons.io.FileUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CoverageHelper {

    private static Logger logger = LoggerFactory.getLogger(CoverageHelper.class);

    Pattern loadPattern = Pattern.compile("load\\(([\'\"].*[\'\"])\\);?");
    Pattern evalPattern = Pattern.compile("eval\\((.*)\\);?");
    private JSONDataMerger jsonMerger = new JSONDataMerger();
    private IoUtils ioUtils = IoUtils.getInstance();
    List<String> coverageFileNames = new ArrayList<>();

    public void prepareForCoverageReport() {
        //1.清空dest目录
        deleteDest();
        logger.info("dest目录清空完成！");

        //2.每次执行代码插桩前注册代码预处理和后处理器
        String[] args = new String[] { "-fs", "js", "target/dest/js", "--exclude=v4","--exclude=v5"};
        SourceHandlerRegister.registSourcePreHandler(source -> {
            Matcher matcher = loadPattern.matcher(source);
            while (matcher.find()) {
                String find = matcher.group();
                source = source.replace(find, find.replace(find, "load('target/dest/" + matcher.group(1).replaceAll("[\"\']", "") + "');")) ;
            }

            matcher = evalPattern.matcher(source);
            while (matcher.find()) {
                String find = matcher.group();
                source = source.replace(find, find.replace(find, "myEval(" + matcher.group(1) + ");")) ;
            }
            return source;
        });
        SourceHandlerRegister.registSourcePostHandler(source -> source.replaceAll("myEval", "eval"));
        Main.main(args);
        logger.info("目标js插桩完成！");

        SourceHandlerRegister.clear();
        String[] args1 = new String[] { "-fs", "testjs", "target/dest/testjs", "--no-instrument=v6","--no-instrument-reg=.*\\.js"};
        SourceHandlerRegister.registSourcePreHandler(source -> {
            Matcher matcher = loadPattern.matcher(source);
            while (matcher.find()) {
                String find = matcher.group();
                String convert = find.replace(find, "load('target/dest/" + matcher.group(1).replaceAll("[\"\']", "") + "');");
                logger.info("转换【 {} -> {} 】", find, convert);

                source = source.replace(find, convert) ;
            }
            return source;
        });
        Main.main(args1);
        logger.info("testjs转换完成！");
    }

    public void coverageToJSON(ScriptEngine scriptEngine, ScriptContext scriptContext, String coverageFileName){
        try {
            String projectPath = getProjectPath();
            String json = (String) scriptEngine.eval("jscoverage_serializeCoverageToJSON();", scriptContext);
            //3、数据写入文件
            FileUtils.writeStringToFile(new File(projectPath + "target/dest/js/" + coverageFileName), json ,"UTF-8");
            coverageFileNames.add(projectPath + "target\\dest\\js\\" + coverageFileName);
        } catch (ScriptException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    public static void deleteDest(){
        File destFolder = new File("target\\dest");
        deleteFolder(destFolder);
    }

    private static void deleteFolder(File destFolder){
        if(destFolder.exists()) {
            Arrays.stream(Objects.requireNonNull(destFolder.listFiles())).forEach(subItem -> {
                if(subItem.isDirectory()){
                    deleteFolder(subItem);
                    subItem.delete();
                } else {
                    subItem.delete();
                }
            });
            destFolder.delete();
        }

    }

    public static String getProjectPath(){
        File directory = new File("");// 参数为空
        String projectPath = "";
        try {
            projectPath = directory.getCanonicalPath();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return projectPath + File.separator;
    }

    public void mergeJSON() {
        String jscoverageJson = coverageFileNames.stream()
                .map(s -> ioUtils.loadFromFileSystem(new File(s)))
                .reduce((first, second) -> jsonMerger.toJSON(jsonMerger.mergeJSONCoverageStrings(first, second))).get();
        try {
            FileUtils.writeStringToFile(new File(getProjectPath() + "target/dest/js/jscoverage.json"), jscoverageJson ,"UTF-8");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}
